\section{Модель памяти в 8086}
\myindex{Intel!8086!Модель памяти}
\myindex{MS-DOS}
\label{8086_memory_model}

Разбирая 16-битные программы для MS-DOS или Win16
(\myref{dongle_16bit_dos} или \myref{win16_near_far_pointers}),
мы можем увидеть, что указатель состоит из двух 16-битных значений.
Что это означает? О да, еще один дивный артефакт MS-DOS и 8086.

8086/8088 был 16-битным процессором, но мог адресовать 20-битное адресное
пространство (таким образом мог адресовать 1MB внешней памяти).
Внешняя адресное пространство было разделено между \ac{RAM} (максимум 640KB),
\ac{ROM}, окна для видеопамяти, EMS-карт, \etc{}.

Припомним также что 8086/8088 был на самом деле наследником 8-битного процессора 8080.
Процессор 8080 имел 16-битное адресное пространство, т.е. мог адресовать только 64KB.
И возможно в расчете на портирование старого ПО\footnote{Автор не уверен на 100\% здесь},
8086 может поддерживать 64-килобайтные
окна, одновременно много таких, расположенных внутри одномегабайтного адресного пространства.
Это, в каком-то смысле, игрушечная виртуализация.
\myindex{x86!\Registers!CS}
\myindex{x86!\Registers!DS}
\myindex{x86!\Registers!ES}
\myindex{x86!\Registers!SS}
Все регистры 8086 16-битные, так что, чтобы адресовать больше, специальные сегментные
регистры (CS, DS, ES, SS) были введены.
Каждый 20-битный указатель вычисляется, используя значения из пары состоящей из сегментного регистра
и адресного регистра (например DS:BX) вот так:

\begin{center}
$real\_address = (segment\_register \ll 4) + address\_register$
\end{center}

Например, окно памяти для графики (\ac{EGA}, \ac{VGA}) на старых IBM PC-совместимых компьютерах
имело размер 64KB.

Для доступа к нему, значение 0xA000 должно быть записано в один из сегментных регистров,
например, в DS.

Тогда DS:0 будет адресовать самый первый байт видеопамяти, а DS:0xFFFF ~--- самый последний байт.

А реальный адрес на 20-битной адресной шине, на самом деле будет от 0xA0000 до 0xAFFFF.

Программа может содержать жесткопривязанные адреса вроде 0x1234, но \ac{OS} может иметь необходимость
загрузить программу по другим адресам, так что она пересчитает значения для сегментных регистров так,
что программа будет нормально работать, не обращая внимания на то,
в каком месте памяти она была расположена.

Так что, любой указатель в окружении старой MS-DOS на самом деле состоял из адреса сегмента
и адреса внутри сегмента, т.е. из двух 16-битных значений. 20-битного значения было бы достаточно для
этого, хотя, тогда пришлось бы вычислять адреса слишком часто: так что передача большего количества
информации в стеке ~--- это более хороший баланс между экономией места и удобством.

Кстати, из-за всего этого, не было возможным выделить блок памяти больше чем 64KB.

\myindex{Intel!80286}
\myindex{Intel!80386}
В 80286 сегментные регистры получили новую роль селекторов, имеющих немного другую функцию.

\myindex{MS-DOS!DOS extenders}
Когда появился процессор 80386 и компьютеры с большей памятью,
MS-DOS была всё еще популярна, так что появились DOS-экстендеры: на самом деле это уже был шаг
к \q{серьезным} \ac{OS}, они переключали \ac{CPU} в защищенный режим и предлагали куда лучшее \ac{API} для
программ, которые всё еще предполагалось запускать в MS-DOS.

Широко известные примеры это DOS/4GW (игра DOOM была скомпилирована под него), Phar Lap, PMODE.

\par
\myindex{Windows!Windows 3.x}
\myindex{Windows!Win32}
Кстати, точно такой же способ адресации памяти был и в 16-битной линейке Windows 3.x, перед Win32.

